﻿using System;
using System.Collections.Generic;
using Moq;
using NUnit.Framework;
using Xenta.Entities;
using Xenta.Enums;
using Xenta.Operations;
using Xenta.Plugins;
using Xenta.Structs;
using Xenta.Utils;

namespace Xenta.Tests.Operations
{
    [TestFixture]
    public class FileTests : OperationTest
    {
        protected override IEnumerable<Type> ModelMappings
        {
            get
            {
                return NHMappings.ALL;
            }
        }

        protected override IDictionary<DependencyInfo, IDependency> Dependencies
        {
            get
            {
                var components = new Dictionary<DependencyInfo, IDependency>();
                var fileStorage = new Mock<IFileStorage>();
                fileStorage.Setup(x => x.Create(It.IsAny<FileEntity>()));
                fileStorage.Setup(x => x.Delete(It.IsAny<FileEntity>()));
                components.Add(new DependencyInfo
                {
                    ID = "52fa95dc-61b3-47b8-af7d-9453d8269d30"
                }, fileStorage.Object);
                return components;
            }
        }

        [TestCase("name", "mime-type", 100)]
        public void Can_CRUD(string name, string mimeType, long size)
        {
            #region Prepare

            var country = Processor.Execute(new CreateCountry
            {
                Code = "xy"
            }).Result;
            var localizationProfile = Processor.Execute(new CreateLocalizationProfile
            {
                Code = "xy",
                LanguageID = Processor.Execute(new CreateLanguage
                {
                    Code = "xy"
                }).Result.EntityID,
                TimeZoneID = Processor.Execute(new CreateTimeZone
                {
                    Code = "xy"
                }).Result.EntityID,
                CurrencyID = Processor.Execute(new CreateCurrency
                {
                    Code = "xy",
                    Rate = 1
                }).Result.EntityID,
                CountryID = country.EntityID,
                RegionID = Processor.Execute(new CreateRegion
                {
                    Code = "xy",
                    CountryID = country.EntityID
                }).Result.EntityID,
                DimensionUnitID = Processor.Execute(new CreateMeasureUnit
                {
                    Code = "xy-dim",
                    Ratio = 1,
                    Flags = MeasureUnitFlags.Dimension
                }).Result.EntityID,
                WeightUnitID = Processor.Execute(new CreateMeasureUnit
                {
                    Code = "xy-weight",
                    Ratio = 1,
                    Flags = MeasureUnitFlags.Weight
                }).Result.EntityID,
                InformationUnitID = Processor.Execute(new CreateMeasureUnit
                {
                    Code = "xy-info",
                    Ratio = 1,
                    Flags = MeasureUnitFlags.Information
                }).Result.EntityID
            }).Result;
            var account = Processor.Execute(new CreateAccount
            {
                Email = "email@example.com",
                Username = "username",
                Password = "password",
                LocalizationProfileID = localizationProfile.EntityID
            }).Result;
            var owner = Processor.Execute(new CreateFileOwner
            {
                AccountID = account.EntityID,
                Quota = size * 2
            }).Result;

            #endregion

            var file = Processor.Execute(new CreateFile
            {
                FolderID = 0,
                OwnerID = owner.EntityID,
                StorageID = Guid.Parse("52fa95dc-61b3-47b8-af7d-9453d8269d30"),
                Name = name,
                MimeType = mimeType,
                Size = size
            }).Result;

            Assert.NotNull(file);
            file.Name.AreEqualIgnoringCase(name);
            file.MimeType.AreEqualIgnoringCase(mimeType);
            file.Size.AreEqual(size);
            file.AreEqual(Processor.Execute(new GetFile
            {
                EntityID = file.EntityID
            }).Result);

            file.AreEqual(Processor.Execute(new GetFileByGuid
            {
                Guid = file.Guid
            }).Result);

            name = name.Reverse();
            var upd_file = Processor.Execute(new UpdateFile
            {
                EntityID = file.EntityID,
                FolderID = 0,
                OwnerID = owner.EntityID,
                Name = name,
                Flags = FileFlags.Active
            }).Result;

            Assert.NotNull(upd_file);
            upd_file.AreEqual(file);
            upd_file.Name.AreEqualIgnoringCase(name);
            upd_file.MimeType.AreEqualIgnoringCase(mimeType);
            upd_file.Size.AreEqual(size);
            upd_file.Flags.AreEqual(FileFlags.Active);

            Processor.Execute(new DeleteFile
            {
                EntityID = file.EntityID
            });
        }

        [TestCase(100)]
        public void Can_Set_Size(long size)
        {
            #region Prepare

            var country = Processor.Execute(new CreateCountry
            {
                Code = "xy"
            }).Result;
            var localizationProfile = Processor.Execute(new CreateLocalizationProfile
            {
                Code = "xy",
                LanguageID = Processor.Execute(new CreateLanguage
                {
                    Code = "xy"
                }).Result.EntityID,
                TimeZoneID = Processor.Execute(new CreateTimeZone
                {
                    Code = "xy"
                }).Result.EntityID,
                CurrencyID = Processor.Execute(new CreateCurrency
                {
                    Code = "xy",
                    Rate = 1
                }).Result.EntityID,
                CountryID = country.EntityID,
                RegionID = Processor.Execute(new CreateRegion
                {
                    Code = "xy",
                    CountryID = country.EntityID
                }).Result.EntityID,
                DimensionUnitID = Processor.Execute(new CreateMeasureUnit
                {
                    Code = "xy-dim",
                    Ratio = 1,
                    Flags = MeasureUnitFlags.Dimension
                }).Result.EntityID,
                WeightUnitID = Processor.Execute(new CreateMeasureUnit
                {
                    Code = "xy-weight",
                    Ratio = 1,
                    Flags = MeasureUnitFlags.Weight
                }).Result.EntityID,
                InformationUnitID = Processor.Execute(new CreateMeasureUnit
                {
                    Code = "xy-info",
                    Ratio = 1,
                    Flags = MeasureUnitFlags.Information
                }).Result.EntityID
            }).Result;
            var account = Processor.Execute(new CreateAccount
            {
                Email = "email@example.com",
                Username = "username",
                Password = "password",
                LocalizationProfileID = localizationProfile.EntityID
            }).Result;
            var owner = Processor.Execute(new CreateFileOwner
            {
                AccountID = account.EntityID,
                Quota = size * 2
            }).Result;

            #endregion

            var file = Processor.Execute(new CreateFile
            {
                FolderID = 0,
                OwnerID = owner.EntityID,
                StorageID = Guid.Parse("52fa95dc-61b3-47b8-af7d-9453d8269d30"),
                Name = "name",
                MimeType = "mimeType",
                Size = size
            }).Result;

            size = size * 2;
            file = Processor.Execute(new SetFileSize
            {
                EntityID = file.EntityID,
                Size = size
            }).Result;

            file.Size.AreEqual(size);
        }

        [Test]
        public void Cannot_Create_If_Size_Lt_Zero()
        {
            Assert.Throws<ApplicationException>(() => Processor.Execute(new CreateFile
            {
                Name = "name",
                MimeType = "mime-type",
                StorageID = Guid.Parse("52fa95dc-61b3-47b8-af7d-9453d8269d30"),
                Size = -1
            }));
        }

        [TestCase("name", "")]
        [TestCase("", "mime-type")]
        public void Cannot_Create_If_NameOrMimeType_Empty(string name, string mimeType)
        {
            Assert.Throws<ApplicationException>(() => Processor.Execute(new CreateFile
            {
                Name = name,
                MimeType = mimeType,
                StorageID = Guid.Parse("52fa95dc-61b3-47b8-af7d-9453d8269d30"),
                Size = 1
            }));
        }

        [TestCase(1073741824)]
        public void Cannot_Create_If_Size_Gt_MaxSize(int maxFileSize)
        {
            Assert.Throws<ApplicationException>(() => Processor.Execute(new CreateFile
            {
                Name = "name",
                MimeType = "mime-type",
                StorageID = Guid.Parse("52fa95dc-61b3-47b8-af7d-9453d8269d30"),
                Size = maxFileSize * 2
            }));
        }

        [TestCase(100)]
        public void Cannot_Create_If_Size_Gt_QuotaReminder(long quota)
        {
            #region Prepare

            var country = Processor.Execute(new CreateCountry
            {
                Code = "xy"
            }).Result;
            var localizationProfile = Processor.Execute(new CreateLocalizationProfile
            {
                Code = "xy",
                LanguageID = Processor.Execute(new CreateLanguage
                {
                    Code = "xy"
                }).Result.EntityID,
                TimeZoneID = Processor.Execute(new CreateTimeZone
                {
                    Code = "xy"
                }).Result.EntityID,
                CurrencyID = Processor.Execute(new CreateCurrency
                {
                    Code = "xy",
                    Rate = 1
                }).Result.EntityID,
                CountryID = country.EntityID,
                RegionID = Processor.Execute(new CreateRegion
                {
                    Code = "xy",
                    CountryID = country.EntityID
                }).Result.EntityID,
                DimensionUnitID = Processor.Execute(new CreateMeasureUnit
                {
                    Code = "xy-dim",
                    Ratio = 1,
                    Flags = MeasureUnitFlags.Dimension
                }).Result.EntityID,
                WeightUnitID = Processor.Execute(new CreateMeasureUnit
                {
                    Code = "xy-weight",
                    Ratio = 1,
                    Flags = MeasureUnitFlags.Weight
                }).Result.EntityID,
                InformationUnitID = Processor.Execute(new CreateMeasureUnit
                {
                    Code = "xy-info",
                    Ratio = 1,
                    Flags = MeasureUnitFlags.Information
                }).Result.EntityID
            }).Result;

            #endregion

            var account = Processor.Execute(new CreateAccount
            {
                Email = "email@example.com",
                Username = "username",
                Password = "password",
                LocalizationProfileID = localizationProfile.EntityID
            }).Result;
            var owner = Processor.Execute(new CreateFileOwner
            {
                AccountID = account.EntityID,
                Quota = quota
            }).Result;

            Assert.Throws<ApplicationException>(() => Processor.Execute(new CreateFile
            {
                OwnerID = owner.EntityID,
                Name = "name",
                MimeType = "mime-type",
                StorageID = Guid.Parse("52fa95dc-61b3-47b8-af7d-9453d8269d30"),
                Size = quota * 2
            }));
        }
    }
}
